﻿using Model;
using System;
using System.Collections.Generic;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Shapes;
using Zellularautomat.Structures;

namespace Zellularautomat
{
	/// <summary>
	/// Interaktionslogik für WindowMain.xaml
	/// </summary>
	public partial class WindowMain : Window
	{
		private Controller controller;
		private List<CellDefinition> cellDefinitions;
		private Dictionary<string, Color> colorsForCells;
		private Preferences preferences;
		private Cell[,] cells;
		private double cellEdgeLength;

		public Cell[,] Cells
		{
			get { return cells; }
			set { cells = value; }
		}

		private Cell cell;
		public Cell Cell
		{
			get { return cell; }
			set { cell = value; }
		}

		public WindowMain()
		{
			controller = new Controller();
			controller.StepCalculated += controller_StepCalculated;
			InitializeComponent();
		}

		#region Events

		private void windowMain_Initialized(object sender, EventArgs e)
		{
			menuCmBxCellType.Items.Add("-- Zelltypen --");
			menuCmBxCellType.SelectedIndex = 0;
		}

		private void menuItmPreferences_Click(object sender, RoutedEventArgs e)
		{
			//TODO zweites mal Öffnen ermöglichen
			WindowPreferences windowPreferences;
			if (preferences == null)
			{
				windowPreferences = new WindowPreferences(controller);
			}
			else
			{
				windowPreferences = new WindowPreferences(controller, cellDefinitions, colorsForCells, preferences);
			}
			windowPreferences.Owner = this;
			if (windowPreferences.ShowDialog() == true)
			{
				preferences = windowPreferences.Preferences;
				cellDefinitions = windowPreferences.CellDefinitions;
				colorsForCells = windowPreferences.ColorsForCells;
				InitSimulation();
			}
		}

		private void menuItmRandomConfig_Click(object sender, RoutedEventArgs e)
		{
			if (preferences == null)
			{
				ErrorHandler.ShowInformation("Bitte legen Sie erst Ihre Einstellungen fest."
					, "Keine Daten vorhanden");
			}
			else
			{
				CreateRandomConfiguration();
				PaintField();
			}
		}

		private void menuItmStart_Click(object sender, RoutedEventArgs e)
		{
			controller.StartSimulation(cells, preferences);
		}

		private void controller_StepCalculated(object sender, StepCalculatedEventArgs e)
		{
			this.cells = e.Field;
			PaintField();
		}

		void rectangle_MouseDown(object sender, MouseButtonEventArgs e)
		{
			if (e.ChangedButton == MouseButton.Left)
			{
				ChangeCellAtLocation((System.Drawing.Point)((Rectangle)sender).Tag);
			}
		}

		void rectangle_MouseEnter(object sender, MouseEventArgs e)
		{
			if (e.LeftButton == MouseButtonState.Pressed)
			{
				ChangeCellAtLocation((System.Drawing.Point)((Rectangle)sender).Tag);
			}
		}

		void rectangle_MouseUp(object sender, MouseButtonEventArgs e)
		{
			if (e.ChangedButton == MouseButton.Right)
			{
				//TODO Attribute anpassen
			}
		}

		#endregion

		#region Work

		private void InitSimulation()
		{
			// Combobox for changing cellTypes in field manually
			InitComboboxForCellTypeSelection();

			InitField();

			InitEdgeLength();

			InitRectangles();
		}

		private void InitComboboxForCellTypeSelection()
		{
			menuCmBxCellType.Items.Clear();
			foreach (var cellDefinition in cellDefinitions)
			{
				menuCmBxCellType.Items.Add(cellDefinition);
			}
			menuCmBxCellType.SelectedItem = cellDefinitions[0];
		}

		private void InitField()
		{
			if (preferences.InitialField != null)
			{
				if (preferences.InitialField.GetLength(0) == preferences.SizeWidth && preferences.InitialField.GetLength(1) == preferences.SizeHeight)
				{
					this.cells = preferences.InitialField;
					return;
				}
				else
				{
					ErrorHandler.ShowInformation("Die initiale Belegung aus den geladenen Einstellungen konnte nicht gewählt werden, weil die Abmessungen des Feldes verändert wurden."
						, "Fehler bei Feldinitialisierung");
				}
			}
			this.cells = new Cell[preferences.SizeWidth, preferences.SizeHeight];
			CreateRandomConfiguration();
		}

		void cell_PropertyChanged(object sender, EventArgs e)
		{
			DrawCell(((Cell)sender).Position.X, ((Cell)sender).Position.Y);
		}

		private void CreateRandomConfiguration()
		{
			Random random = new Random();
			for (int x = 0; x < cells.GetLength(0); x++)
			{
				for (int y = 0; y < cells.GetLength(1); y++)
				{
					double rd = random.NextDouble();
					double sum = 0;
					int index = 0;
					foreach (double value in preferences.CellDistribution.Values)
					{
						sum += value;
						if (sum >= rd)
						{
							break;
						}
						index++;
					}

					cells[x, y] = new Cell(cellDefinitions[index], new System.Drawing.Point(x, y));
					cells[x, y].PropertyChanged += cell_PropertyChanged;
				}
			}
		}

		private void InitEdgeLength()
		{
			//cells should be squares, so their edge length should be minimum
			double absHeight = stPanelMain.ActualHeight - mainMenu.ActualHeight;
			double absWidth = stPanelMain.ActualWidth;
			cellEdgeLength = Math.Min((absHeight / preferences.SizeHeight), (absWidth / preferences.SizeWidth));
		}

		private void InitRectangles()
		{
			for (int y = 0; y < cells.GetLength(1); y++)
			{
				RowDefinition rd = new RowDefinition();
				rd.Height = new GridLength(cellEdgeLength);
				gridField.RowDefinitions.Add(rd);
			}

			for (int x = 0; x < cells.GetLength(0); x++)
			{
				ColumnDefinition cd = new ColumnDefinition();
				cd.Width = new GridLength(cellEdgeLength);
				gridField.ColumnDefinitions.Add(cd);

				for (int y = 0; y < cells.GetLength(1); y++)
				{
					Rectangle r = new Rectangle()
					{
						Width = cellEdgeLength,
						Height = cellEdgeLength,
						Fill = new SolidColorBrush(colorsForCells[cells[x, y].CellDefinition.Name]),
						Tag = new System.Drawing.Point(x, y)
					};
					r.MouseEnter += rectangle_MouseEnter;
					r.MouseDown += rectangle_MouseDown;
					r.MouseUp += rectangle_MouseUp;
					gridField.Children.Add(r);
					Grid.SetColumn(r, x);
					Grid.SetRow(r, y);
				}
			}
			gridField.Width = cells.GetLength(0) * cellEdgeLength;
			gridField.Height = cells.GetLength(1) * cellEdgeLength;
		}

		private void ChangeCellAtLocation(System.Drawing.Point location)
		{
			if (preferences != null && colorsForCells.ContainsKey(((CellDefinition)menuCmBxCellType.SelectedItem).Name))
			{
				ChangeCell(ref cells[location.X, location.Y]);
			}
		}

		private void ChangeCell(ref Cell currentCell)
		{
			CellDefinition cellDef = (CellDefinition)menuCmBxCellType.SelectedItem;
			currentCell.ChangeCellDefinition(cellDef);
		}

		private void PaintField()
		{
			if (cells == null)
			{
				return;
			}
			for (int x = 0; x < cells.GetLength(0); x++)
			{
				for (int y = 0; y < cells.GetLength(1); y++)
				{
					DrawCell(x, y);
				}
			}
		}

		private void DrawCell(int x, int y)
		{
			((Rectangle)gridField.Children[cells.GetLength(0) * x + y]).Fill = new SolidColorBrush(colorsForCells[cells[x, y].CellDefinition.Name]);
		}

		#endregion
	}
}
